import cv2
import numpy as np
import copy


def mergeTwoLayers(bottom_layer: np.ndarray, top_layer: np.ndarray) -> np.ndarray:
    bottom_layer, top_layer = bottom_layer.transpose(
        [2, 0, 1]), top_layer.transpose([2, 0, 1])
    if top_layer.shape[0] == 3:
        return top_layer
    bgr1, alpha1 = bottom_layer[:3, :, :], bottom_layer[3,
                                                        :, :]/255.0 if bottom_layer.shape[0] == 4 else 1.0
    bgr2, alpha2 = top_layer[:3, :, :], top_layer[3, :, :]/255.0
    result = np.empty(top_layer.shape, np.float64)
    result[:3, :, :] = alpha2*bgr2 + alpha1*(1-alpha2)*bgr1
    result[3, :, :] = 1 - (1 - alpha1)*(1-alpha2) + 1e-10
    result[:3, :, :] = result[:3, :, :] / result[3, :, :]
    result[3, :, :] = result[3, :, :] * 255
    result = result + 0.5
    result = result.astype(np.uint8)
    result = result.transpose([1, 2, 0])
    return result


def mgergeLayers(layer_list: list[np.ndarray]) -> np.ndarray:
    result = layer_list[0]
    for layer in layer_list[1:]:
        result = mergeTwoLayers(result, layer)
    return result


def paste(canvas: np.ndarray, image: np.ndarray, shift: tuple[int, int]) -> np.ndarray:
    result = canvas.copy()
    # 获取画布和图片的形状
    canvas_h, canvas_w = canvas.shape[:2]
    image_h, image_w = image.shape[:2]
    # 获取图片左上角在画布上的坐标
    y, x = shift
    # 计算图片右下角在画布上的坐标
    x2 = min(x + image_w, canvas_w)
    y2 = min(y + image_h, canvas_h)
    # 计算图片在画布上的有效区域
    x1 = max(x, 0)
    y1 = max(y, 0)
    # 计算图片在自身上的有效区域
    ix1 = max(-x, 0)
    iy1 = max(-y, 0)
    ix2 = ix1 + (x2 - x1)
    iy2 = iy1 + (y2 - y1)
    # 将图片粘贴到画布上
    result[y1:y2, x1:x2] = mergeTwoLayers(
        result[y1:y2, x1:x2], image[iy1:iy2, ix1:ix2])[:, :, :canvas.shape[2]]
    # 返回画布
    return result


def pinnedPaste(canvas: np.ndarray, logo: np.ndarray, canvas_center: tuple[float, float], logo_center: tuple[float, float]) -> np.ndarray:
    '''
    - place a scaled rgba format logo on a canvas
    - this function makes sure that the canvas's center point will always the pinned with the logo's center point in the result image
    - logo will be scaled by 'logo_scale'

    Args:
        canvas (np.ndarray): the image to place logo on
        logo (np.ndarray): a rgba format logo image, which will be scaled by logo_scale and placed on canvas
        canvas_center (tuple[float, float]): two real number between 0.0-1.0, (xw, xh), it's canvas'fixed point, logo's center point will overlap with it in the final image
        logo_center (tuple[float, float]): two real number between 0.0-1.0, (xw, xh), it's logo's fixed point, logo will be placed so that this point on the image will overlap with the fiexed point of canvas
    '''
    result = copy.deepcopy(canvas)
    canvas_h, canvas_w = canvas.shape[:2]
    logo_h, logo_w = logo.shape[:2]

    h = round(canvas_center[1] * canvas_h - logo_center[1] * logo_h)
    w = round(canvas_center[0] * canvas_w - logo_center[0] * logo_w)
    result = paste(canvas, logo, [h, w])
    return result

# 边缘羽化效果


def EdgeGaussianBlur(image: np.ndarray, radius: int, sigma: float, border_type: str = 'padding') -> np.ndarray:
    morph_ksize = round(2*sigma + 1)
    kernel = cv2.getStructuringElement(
        cv2.MORPH_ELLIPSE, (morph_ksize, morph_ksize))
    if border_type == 'padding':
        result = cv2.copyMakeBorder(
            image, radius, radius, radius, radius, cv2.BORDER_CONSTANT, value=(0, 0, 0, 0))
    elif border_type == 'same':
        result = image.copy()
    mask = cv2.erode(result[:, :, 3], kernel)
    ksize = radius*2 + 1
    mask = cv2.GaussianBlur(mask, (ksize, ksize), sigma)
    result[:, :, 3] = mask
    return result


def resizeByScale(image: np.ndarray, scale: float) -> np.ndarray:
    image_h, image_w = image.shape[:2]
    new_h, new_w = round(image_h * scale), round(image_w * scale)
    result = cv2.resize(image, (new_w, new_h), interpolation=cv2.INTER_AREA)
    return result


if __name__ == '__main__':
    pass
